#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#define SERV_PORT 9527

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}


//读回调函数
void read_cb(struct bufferevent *bev, void *arg)
{
	char buf[1024] = {0};
	bufferevent_read(bev, buf, sizeof(buf));
	printf("client data: %s\n", buf);

	char *p = "I'm server\n";
	bufferevent_write(bev, p, strlen(p)+1);

	sleep(1);
}


//写回调函数,没什么用，因为在读回调里已经写回去了，这里只能通知一下，服务器写数据成功了
void write_cb(struct bufferevent *bev, void *arg)
{
	printf("write success\n");
}


//事件回调
void event_cb(struct bufferevent *bev, short events, void *arg)
{
	if (events & BEV_EVENT_EOF)  
    {
		printf("connection closed\n");
	}
	else if(events & BEV_EVENT_ERROR)
	{
		printf("some other error\n");
	}

	bufferevent_free(bev);
	printf("buffevent 资源已经被释放...\n");
}


//监听回调函数
void cb_listener(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *serv_addr, int len, void *ptr )
{  
	printf("new client connected\n");

	struct event_base* base = (struct event_base*) ptr;//接收传进来的base，因为base不是全局变量，所以不能直接用，需要传进来

	struct bufferevent *bev;//创建bufferevent
	bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
	
	bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);//设置bufferevent的回调，写回调与事件回调一般没啥用，可以传null,最后一个参数是传给读、写、事件回调里的void *arg
	bufferevent_enable(bev, EV_READ);//启用bufferevent的读缓冲，默认是关闭的
}


int main(int argc, char *argv[])
{	
	struct sockaddr_in serv_addr;

	bzero(&serv_addr, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);//本地字节序转网络字节序
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	struct event_base* base = event_base_new();//创建底座

	struct evconnlistener* listener;//创建监听器，将socket bind listen accept合并到一起了
	listener= evconnlistener_new_bind(base, cb_listener, base, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 36, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

	event_base_dispatch(base);//循环监听

	//释放
	evconnlistener_free(listener);
	event_base_free(base);

    return 0;
}

